package com.zhiwei.version.git.service.impl;

import com.zhiwei.common.util.DateUtil;
import com.zhiwei.version.git.entity.GitCommitLog;
import com.zhiwei.version.git.service.GitRepositoryService;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.RefSpec;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * function
 * author zhiwei.yang
 * time 2020-3-4-11:06
 */
@Service
public class GitRepositoryServiceImpl implements GitRepositoryService {

    @Override
    public Git cloneRepository(String repoUrl, String cloneDir, CredentialsProvider provider) throws GitAPIException {
        return Git.cloneRepository()
                .setCredentialsProvider(provider)
                .setURI(repoUrl)
                .setDirectory(new File(cloneDir)).call();
    }

    @Override
    public void commitRepository(Git git, String message, CredentialsProvider provider) throws GitAPIException {
        git.add().addFilepattern(".").call();
        git.commit().setMessage(message).call();
    }

    @Override
    public void pushRepository(Git git, CredentialsProvider provider) throws GitAPIException, IOException {
        this.pushRepository(git, null, provider);
    }

    @Override
    public void pushRepository(Git git, String branch, CredentialsProvider provider) throws GitAPIException, IOException {
        if (branch == null) {
            //获取当前分支
            branch = git.getRepository().getBranch();
        }
        git.push()
                .setCredentialsProvider(provider)
                .setRemote("origin")
                .setRefSpecs(new RefSpec(branch))
                .call();
    }

    @Override
    public Repository getLocalRepository(String localGitDir) throws IOException {
        Git git = getLocalGit(localGitDir);
        return null == git ? null : git.getRepository();
    }

    @Override
    public Git getLocalGit(String localGitDir) throws IOException {
        if(StringUtils.isEmpty(localGitDir)){
            return null;
        }
        File repositoryDir = new File(localGitDir);
        if(!repositoryDir.exists() || !repositoryDir.isDirectory()){
            return null;
        }
        return Git.open(repositoryDir);
    }

    @Override
    public List<GitCommitLog> getRepositoryLog(Git git) throws IOException {
        return getSinceCommitRepositoryLog(git, null);
    }

    @Override
    public List<GitCommitLog> getSinceCommitRepositoryLog(Git git, String commitId) throws IOException {
        return getBranchSinceCommitRepositoryLog(git, null, commitId);
    }

    @Override
    public List<GitCommitLog> getBranchSinceCommitRepositoryLog(Git git, String branch, String commitId) throws IOException {
        Repository repository = git.getRepository();
        if(null == repository){
            return Collections.emptyList();
        }
        if (branch == null) {
            branch = repository.getBranch();
        }
        Ref head = repository.findRef("refs/heads/" + branch);
        List<GitCommitLog> commitLogList = new ArrayList<>();
        if (head != null) {
            try (RevWalk revWalk = new RevWalk(repository)) {
                revWalk.markStart(revWalk.parseCommit(head.getObjectId()));
                for (RevCommit revCommit : revWalk) {
                    if (revCommit.getId().getName().equals(commitId)) {
                        break;
                    }
                    GitCommitLog gitCommitLog = GitCommitLog.builder()
                            .id(revCommit.getId().getName())
                            .time(DateUtil.parseDate(revCommit.getCommitTime()))
                            .parentCount(revCommit.getParentCount())
                            .name(revCommit.getCommitterIdent().getName())
                            .email(revCommit.getCommitterIdent().getEmailAddress())
                            .msg(revCommit.getFullMessage().replaceAll("[\r\n]", ""))
                            .build();
                    commitLogList.add(gitCommitLog);
                }
                revWalk.dispose();
            }
        }
        return commitLogList;
    }
}
